# -*- coding: utf-8 -*-

import pygame
from pygame.locals import *

import random

import game
from game import Vec2d
from game import Map
from game import Unit
from game import FloatingText
from game import Chain
from game import Projectile
from game import Pathfinder

from gui import Gui
from gui import Label
from gui import HpBar
from gui import Button

import sprite

import event

def main():
    pygame.init()
    pygame.font.init()
    pygame.display.set_caption('COS')

    cont = True
    while cont:
        cont = start_game()

    pygame.quit()


def create_monster(level=1):
    pos = Vec2d(random.uniform(0, 1200), random.uniform(0, 1200))
    while (Map.game_map.collide(pos, 16)):
        pos = Vec2d(random.uniform(0, 1200), random.uniform(0, 1200))

    m = Unit(pos.x, pos.y)
    m.team = 1
    m.type = random.randint(0, 1)

    if m.type == Unit.MONSTER_MELEE:
        m.attack_power = 10.0
        m.max_hp = 250.0
        m.hp = m.max_hp
        m.speed = 0.12
        m.attack_swing_delay = 400
        m.set_color(pygame.Color(255, 128, 0))
        m.model = Map.sprite_loader.load_model('baldric')
    else:
        m.attack_power = 10.0
        m.max_hp = 120.0
        m.hp = m.max_hp
        m.speed = 0.06
        m.attack_swing_delay = 500
        m.attack_speed = 0.6
        m.range = 300
        m.set_color(pygame.Color(255, 0, 128))
        m.model = Map.sprite_loader.load_model('mage')

    for i in range(level - 1):
        m.level_up()
    return m

def create_ally(player, name="Ally"):
    #create an ally at random direction within 200-300 range
    pos = get_random_position_from_position(player.position, 200, 300)
    while (Map.game_map.collide(pos, 16)):
        pos = get_random_position_from_position(player.position, 200, 300)

    a = Unit(pos.x, pos.y)
    a.team = 0
    a.name = name
    a.attack_power = 4.0
    a.max_hp = 150.0
    a.hp = a.max_hp
    a.speed = 0.12
    #m.attack_swing_delay = 400
    a.attack_speed = 0.8
    a.range = 400
    a.set_color(pygame.Color(0, 196, 0))

    return a

def get_random_position_from_position(source, min_distance, max_distance):
    #create an ally at random direction within 200-300 range
    distance = random.uniform(min_distance, max_distance)
    direction = Vec2d(0, 1)
    direction.angle = random.randint(0, 359)

    random_pos = source + (direction * distance)
    return random_pos

def do_ai(duration):
    #AI
    for monster in Map.monster_list:
        if monster.alive == True:
            #simple AI
            monster.next_decision -= duration

            if not monster.path:
                monster.next_decision = -1

            # check if any target is near, attack him if it is
            #nearest_target = Map.get_nearest_unit(Map.ally_list, monster.position)
            nearest_target = Map.player
            if nearest_target != None and monster.next_decision < 0:
                monster.next_decision = random.randint(1000, 2000)

                """
                target_distance = monster.position.get_distance(nearest_target.position)
                
                if monster.type == Unit.MONSTER_MELEE:
                    agro_distance = 3000
                else:
                    agro_distance = 3000
                
                if target_distance <= agro_distance:
                    monster.target = nearest_target
                    monster.next_decision = 1  # reset wandering decision
                else:
                    monster.target = None
                """
                monster.target = nearest_target

                # attempt to shoot target (Range mob)
                if monster.target != None and monster.type == Unit.MONSTER_RANGE:

                    target_distance = monster.position.get_distance(monster.target.position)
                    if target_distance <= monster.range:
                        projectile = monster.shoot(monster.target.position)
                        if projectile != None:
                            Map.projectile_list.append(projectile)
                            monster.destination = monster.position
                            monster.path = []
                    else:
                        monster.find_path(monster.target.position)

                    #monster.target = None  #Clear target so it wont move near

                if monster.type == Unit.MONSTER_MELEE and monster.target != None:
                    monster.find_path(monster.target.position)

            """
            # if no target around, then start "wandering"
            if monster.target == None and monster.next_decision < 0:
                monster.next_decision = random.randint(0, 5000)
                x = random.randint(-300, 300) + monster.position.x;
                y = random.randint(-300, 300) + monster.position.y;

                monster.destination = Vec2d(x, y)
            """

            #end AI

    for ally in Map.ally_list:
        if ally == Map.player:
            continue

        elif ally.alive == True:
            #AI
            # check if player is near, if too far follow the player
            player_distance = ally.position.get_distance(Map.player.position)

            if player_distance > 220:
                ally.destination = get_random_position_from_position(Map.player.position, 100, 200)
                ally.find_path(ally.destination)
                #a.target = None # Remove target

            nearest_monster = Map.get_nearest_unit(Map.monster_list, ally.position)
            if nearest_monster != None and ally.position.get_distance(nearest_monster.position) <= ally.range:

                # Chain Lightning!
                if ally.attack():
                    direction = nearest_monster.position - ally.position

                    modifier = (1.0 + (ally.level / 2.0))
                    if modifier >= 2.0: modifier = 2.0

                    projectile = Chain()
                    projectile.position = ally.position
                    projectile.direction = direction.normalized()
                    projectile.damage = ally.attack_power * modifier
                    projectile.set_range(ally.range)
                    projectile.owner = ally
                    Map.projectile_list.append(projectile)


def do_gui():
    gui = Gui()
    gui.size = Vec2d(240, 400)
    gui.position = Vec2d(5, 5)

    bar_x = 0
    bar_y = 20

    ally = Map.ally_list

    for a in ally:
        label = Label()
        label.text = a.name
        label.size = Vec2d(200, 20)
        label.position = Vec2d(bar_x, bar_y)
        label.font_size = 15
        label.alignment_x = Gui.LEFT
        label.alignment_y = Gui.BOTTOM
        label.color = pygame.Color(255, 255, 255)
        gui.add(label)

        bar_y += 20

        hpbar = HpBar()
        hpbar.size = Vec2d(200, 20)
        hpbar.position = Vec2d(bar_x, bar_y)
        hpbar.value = a.hp
        hpbar.max = a.max_hp
        hpbar.color = pygame.Color(0, 255, 0)
        hpbar.background_color = pygame.Color(0, 0, 0)
        hpbar.border = 2
        gui.add(hpbar)

        bar_y += 30
        Map.hpbar_player = hpbar

    # FPS Label
    label = Label()
    label.text = str(0)
    label.size = Vec2d(50, 20)
    label.position = Vec2d(0, 0)
    label.font_size = 15
    label.alignment_x = Gui.LEFT
    label.alignment_y = Gui.BOTTOM
    label.color = pygame.Color(255, 255, 0)
    gui.add(label)
    Map.label_fps = label

    button = Button()
    button.text = "Button"
    button.size = Vec2d(100, 20)
    button.position = Vec2d(bar_x, bar_y)
    button.color = pygame.Color(255, 192, 0)
    button.background_color = pygame.Color(0, 64, 64)
    button.border = 2
    gui.add(button)

    """
    mousedown = pygame.mouse.get_pressed()
    realmousepos = pygame.mouse.get_pos()

    if button.get_rect().collidepoint(realmousepos):
        if mousedown[0]:
            if button.state == Button.HOVER:
                button.pressed = True

            button.state = Button.PRESSED
        else:
            if button.pressed:
                print "Button Clicked!"

            button.state = Button.HOVER
            button.pressed = False

    else:
        button.pressed = False
        button.state = Button.NORMAL
    """

    return gui

def start_game():
    screen = pygame.display.set_mode((1024, 768))
    clock = pygame.time.Clock()

    game_map = Map("data/map/desert.tmx")
    Map.game_map = game_map
    Map.sprite_loader = sprite.SpriteLoader()
    player_data = Map.game_map.resource_manager.get_unit("player.json")
    player = Unit(200, 400)

    # TODO: Unit Factory
    player.name = player_data["name"]
    player.max_hp = player_data["hp"]
    player.hp = player.max_hp
    player.attack_power = player_data["attack_power"]
    player.attack_speed = 2
    player.range = 400
    player.model = Map.sprite_loader.load_model(player_data["model"])

    ally = []
    ally.append(player)
    #ally.append(create_ally(player, "Ally 1"))
    #ally.append(create_ally(player, "Ally 2"))
    #ally.append(create_ally(player, "Ally 3"))

    monster = []
    for i in range(5):
        monster.append(create_monster())


    projectile = []


    time = 0
    last_render = 0
    spawn_time = 12000

    Map.event = event.Event()
    event.TriggerKeyUp(Map.event)
    event.TriggerQuitGame(Map.event)
    event.TriggerLeftMouseStateDown(Map.event)
    event.TriggerRightMouseStateDown(Map.event)
    event.TriggerUnitDamage(Map.event)
    event.TriggerUnitHeal(Map.event)
    event.TriggerUnitDeath(Map.event)
    event.TriggerSkillCasted(Map.event)
    event.TriggerFireballExplode(Map.event)
    event.TriggerProjectileHit(Map.event)
    event.TriggerChainLightningHit(Map.event)
    event.TriggerSkillMultiShot(Map.event)
    event.TriggerSkillChainLightning(Map.event)
    event.TriggerSkillWave(Map.event)
    event.TriggerSkillFireball(Map.event)
    event.TriggerSkillHeal(Map.event)

    #currently just put all in Map static member
    Map.game_map = game_map
    Map.monster_list = monster
    Map.ally_list = ally
    Map.projectile_list = projectile
    Map.player = player
    Map.all_unit = ally + monster
    Map.dead_unit_list = []
    Map.effect_list = []
    Map.buff_list = []
    Map.mouse_target = None
    Map.game_over = False
    Map.run = True

    Map.game_map.generate_pathnode()

    #UI
    gui = do_gui()

    end_game_timer = None

    while Map.run:
        duration = clock.tick(120)
        time += duration
        Map.fps = clock.get_fps()
        Map.label_fps.text = str(Map.fps)

        Map.all_unit = Map.ally_list + Map.monster_list + Map.dead_unit_list

        # monster spawn timer
        spawn_time -= duration
        if spawn_time < 0 and time < 60000:
            spawn_time += 15000
            for i in range(5):
                Map.monster_list.append(create_monster())

        Map.event.handle_pygame_event()
        if Map.game_over: continue

        do_ai(duration)

        for unit in Map.all_unit:
            unit.update(duration)

            if not unit.alive:
                if unit not in Map.dead_unit_list:
                    Map.dead_unit_list.append(unit)

            #if not unit.alive and unit.anim == Unit.ANIM_IDLE:
                if unit in Map.ally_list: Map.ally_list.remove(unit)
                if unit in Map.monster_list: Map.monster_list.remove(unit)

        for projectile in Map.projectile_list:
            projectile.update(duration)

            if projectile.alive == False:
                Map.projectile_list.remove(projectile)

        for effect in Map.effect_list:
            effect.update(duration)

            if effect.alive == False:
                Map.effect_list.remove(effect)

        for buff in Map.buff_list:
            buff.update(duration)

            if buff.alive == False:
                Map.buff_list.remove(buff)

        Map.hpbar_player.value = player.hp

        #rendering
        if (time - last_render) > 40:
        #if False:
            game_map.set_focus(player.position)
            map_buffer = game_map.render(screen)
            for unit in Map.all_unit:
                unit.render(map_buffer)

            for projectile in Map.projectile_list:
                projectile.render(map_buffer)

            for effect in Map.effect_list:
                effect.render(map_buffer)

            screen.fill(pygame.Color(0, 0, 0))
            screen.blit(map_buffer, (-game_map.offset.x, -game_map.offset.y))

            gui.render(screen)
            last_render = time

        if player.alive == False:
            if end_game_timer is None:
                end_game_timer = 2000
            else:
                end_game_timer -= duration
                if end_game_timer <= 0:
                    Map.game_over = True
                    end_message = "GAME OVER"

        if len(Map.monster_list) == 0 and time > 60000:
            if end_game_timer is None:
                end_game_timer = 2000
            else:
                end_game_timer -= duration
                if end_game_timer <= 0:
                    Map.game_over = True
                    end_message = "YOU WIN"

        if Map.game_over:
            f = pygame.font.Font(pygame.font.get_default_font(), 40)
            end_text = f.render(end_message, 1, (255, 255, 255))
            rect = end_text.get_rect()
            rect.center = (1024 / 2, 768 / 2)
            screen.fill(pygame.Color(64, 64, 64, 128), None, BLEND_RGBA_SUB)
            screen.blit(end_text, rect.topleft)

            f = pygame.font.Font(pygame.font.get_default_font(), 20)
            #end_text2 = f.render("Press any key to restart. Press ESC to Quit", 1, (255, 255, 255))
            end_text2 = f.render("Press ESC to Quit", 1, (255, 255, 255))
            rect = end_text2.get_rect()
            rect.center = (1024 / 2, 768 / 2 + 60)
            screen.blit(end_text2, rect.topleft)

        pygame.display.flip()

if __name__ == "__main__":
    main()



